package airport.client.widget.vol;

import airport.client.Airport;
import airport.client.utils.Constantes;
import airport.shared.beans.HotelBean;
import airport.shared.beans.UserBean;
import airport.shared.beans.VolBean;
import airport.shared.service.*;
import com.google.gwt.cell.client.*;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.user.datepicker.client.DatePicker;
import com.google.gwt.view.client.DefaultSelectionEventManager;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.SelectionChangeEvent;

import java.util.ArrayList;
import java.util.Date;
import java.util.Set;

/**
 * Created by Romain on 28/02/15.
 */
public class VolWB extends Airport {
	ArrayList<VolBean> vols;
	ArrayList<HotelBean> hotels = new ArrayList<HotelBean>();

	final MultiSelectionModel<HotelBean> selectionModel = new MultiSelectionModel<>();

	Date dd;
	Date da;
	CellTable<VolBean> tab_vols = new CellTable<>();
	CellTable<HotelBean> tab_hotels = new CellTable<>();
	ListDataProvider<VolBean> ldp = new ListDataProvider<>();
	VolBean selected_vol;
	Set<HotelBean> selected_hotels;

	FlowPanel mainPanel = new FlowPanel();
	FlowPanel savePanel = new FlowPanel();
	FlowPanel consultPanel = new FlowPanel();
	FlowPanel updatePanel = new FlowPanel();
	FlowPanel flowPanel1 = new FlowPanel();
	FlowPanel flowPanel2 = new FlowPanel();
	FlowPanel panelG = new FlowPanel();
	FlowPanel panelD = new FlowPanel();
	FlowPanel panelB = new FlowPanel();

	Label label_titre = new Label();
	Label label_d = new Label("Origine");
	Label label_a = new Label("Destination");
	Label label_h = new Label("Associer un ou plusieurs hôtels");

	FlowPanel htmlSpan = new FlowPanel("span");

	DatePicker picker_date_d = new DatePicker();
	ListBox timePicker_d = timePicker();
	TextBox textbox_lieu_d = new TextBox();

	DatePicker picker_date_a = new DatePicker();
	ListBox timePicker_a = timePicker();
	TextBox textbox_lieu_a = new TextBox();

	DoubleBox doublebox_tarif = new DoubleBox();
	Button button_submit = new Button();
	Button button_retour = new Button();

	public VolWB(int tabPanel) {
		infoDangerHide();
		initWidget(mainPanel);
		checkLogin(tabPanel);
	}

	public void checkLogin(final int tabPanel) {
		final AirportServiceAsync connexionIface;
		connexionIface = GWT.create(AirportService.class);

		connexionIface.checkLogin(new AsyncCallback<UserBean>() {

			@Override
			public void onFailure(Throwable caught) {
				infoDanger(caught.toString());
			}

			@Override
			public void onSuccess(UserBean result) {
				if (result != null) {
					labelTitre.getElement().setInnerHTML("Bienvenue " + result.getPrenom() + " " + result.getNom());
					htmlSpan.setStyleName("add-on");
					htmlSpan.getElement().setInnerHTML("€");

					switch (tabPanel) {
						case 1:
							loadVols();
							break;
						case 2:
							mainPanel.add(label_titre);
							FlowPanel hr = new FlowPanel("hr");
							mainPanel.add(hr);
							loadHotels();
							break;
						default:
							break;
					}
				} else {
					initbouton(false);
					History.newItem(Constantes.ACCUEILWB);
				}
			}
		});
	}

	private void loadConsultPanel() {
		label_titre.setStyleName("nav-header");
		label_titre.setText("Tous les vols");

		tab_vols.setStyleName("table table-bordered");
		addVolColumns();

		SimplePager pager = new SimplePager();
		pager.setDisplay(tab_vols);
		pager.setPageSize(6);

		consultPanel.add(tab_vols);
		consultPanel.add(pager);
		mainPanel.add(consultPanel);
	}

	private void loadSavePanel() {
		consultPanel.setVisible(false);
		savePanel.setVisible(true);
		updatePanel.setVisible(false);

		buildHotelTable();
		loadVolForm(savePanel);

		label_titre.setText("Ajouter un vol");

		button_submit.setText("Enregistrer");
		button_retour.setVisible(false);

		addClickHandler_save(button_submit);
	}

	private void loadUpdatePanel() {
		consultPanel.setVisible(false);
		savePanel.setVisible(false);
		updatePanel.setVisible(true);

		selectionModel.clear();

		for (HotelBean hotelbean : hotels) {
			for (HotelBean hotelselected : selected_vol.getHotels()) {
				if (hotelbean.getIdhotel() == hotelselected.getIdhotel())
					selectionModel.setSelected(hotelbean, true);
			}
		}

		label_titre.setText("Modifier un vol");
		textbox_lieu_d.setText(selected_vol.getLieu_D());
		textbox_lieu_a.setText(selected_vol.getLieu_A());
		doublebox_tarif.setValue(selected_vol.getTarif().doubleValue());
		timePicker_d.setSelectedIndex(selected_vol.getDate_D().getHours());
		timePicker_a.setSelectedIndex(selected_vol.getDate_A().getHours());
		picker_date_d.setValue(selected_vol.getDate_D());
		picker_date_d.setCurrentMonth(selected_vol.getDate_D());
		picker_date_a.setValue(selected_vol.getDate_A());
		picker_date_a.setCurrentMonth(selected_vol.getDate_A());
		dd = selected_vol.getDate_D();
		da = selected_vol.getDate_A();

		button_retour.setVisible(true);

		button_submit.setText("Mettre à jour");
		button_retour.setText("Retour");
	}

	private void loadVolForm(FlowPanel panel) {
		ddChanged();
		daChanged();

		flowPanel1.setStyleName("row-fluid");
		flowPanel2.setStyleName("row-fluid");

		label_titre.setStyleName("nav-header");
		label_d.setStyleName("nav-header");
		label_a.setStyleName("nav-header");
		label_h.setStyleName("nav-header spaced-label");

		textbox_lieu_d.setStyleName("textbox_gauche");
		textbox_lieu_d.setHeight("30");
		textbox_lieu_d.getElement().setPropertyString(Constantes.PLACEHOLDER, "Ville de départ");

		textbox_lieu_a.setStyleName("textbox_gauche");
		textbox_lieu_a.setHeight("30");
		textbox_lieu_a.getElement().setPropertyString(Constantes.PLACEHOLDER, "Ville d'arrivée");

		doublebox_tarif.setStyleName("textbox_tarif");
		doublebox_tarif.setHeight("30");
		doublebox_tarif.getElement().setPropertyString(Constantes.PLACEHOLDER, "Tarif");

		timePicker_d.setStyleName("textbox_heure");
		timePicker_d.setHeight("30");
		timePicker_a.setStyleName("textbox_heure");
		timePicker_a.setHeight("30");

		button_submit.setStyleName("btn spaced");
		button_submit.setHeight("30");
		button_submit.setWidth("140");

		button_retour.setStyleName("btn spaced");
		button_retour.setHeight("30");
		button_retour.setWidth("140");

		button_retour.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				consultPanel.setVisible(true);
				updatePanel.setVisible(false);
				label_titre.setText("Tous les vols");
			}
		});

		panelG.setStyleName("span4");
		panelG.add(label_d);
		panelG.add(picker_date_d);
		panelG.add(textbox_lieu_d);
		panelG.add(timePicker_d);

		panelD.setStyleName("span4");
		panelD.add(label_a);
		panelD.add(picker_date_a);
		panelD.add(textbox_lieu_a);
		panelD.add(timePicker_a);

		panelB.setStyleName("input-append");
		panelB.add(doublebox_tarif);
		panelB.add(htmlSpan);

		flowPanel1.add(panelG);
		flowPanel1.add(panelD);
		flowPanel2.add(panelB);

		panel.add(flowPanel1);
		panel.add(flowPanel2);

		SimplePager pager = new SimplePager();
		pager.setDisplay(tab_hotels);
		pager.setPageSize(6);

		panel.add(label_h);
		panel.add(tab_hotels);
		panel.add(pager);

		panel.add(button_submit);
		panel.add(button_retour);

		mainPanel.add(panel);
	}

	private void buildHotelTable() {
		tab_hotels.setStyleName("table table-bordered");
		addHotelColumns();

		tab_hotels.setSelectionModel(selectionModel,
				DefaultSelectionEventManager.<HotelBean>createCheckboxManager());

		selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
			@Override
			public void onSelectionChange(SelectionChangeEvent event) {
				selected_hotels = selectionModel.getSelectedSet();
			}
		});
	}

	private ListBox timePicker() {
		ListBox lb = new ListBox();

		for (String hour : Constantes.hours) {
			lb.addItem(hour);
		}

		lb.setSelectedIndex(14);

		return lb;
	}

	private void addClickHandler_save(Button button) {
		button.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                save();
            }
        });
    }

	private void addClickHandler_update(Button button) {
		button.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				update();
			}
		});
	}

	private void ddChanged() {
		picker_date_d.addValueChangeHandler(new ValueChangeHandler<Date>() {
            @Override
            public void onValueChange(ValueChangeEvent<Date> event) {
                dd = event.getValue();
            }
        });
    }

	private void daChanged() {
		picker_date_a.addValueChangeHandler(new ValueChangeHandler<Date>() {
            @Override
            public void onValueChange(ValueChangeEvent<Date> event) {
                da = event.getValue();
            }
        });
    }

	private void save() {
		if (dd == null
				|| da == null
				|| textbox_lieu_d.getText().length() == 0
				|| textbox_lieu_a.getText().length() == 0
				|| doublebox_tarif.getText().length() == 0
				|| selected_hotels == null
				|| selected_hotels.size() == 0) {
			infoDanger("Informations incomplètes");
			return;
		}

		setHourAndMinutes(dd, timePicker_d);
		setHourAndMinutes(da, timePicker_a);

		if (dd.after(da)) {
			infoDanger("La date de départ doit être antérieure à la date d'arrivée");
			return;
		}

		VolBean volBean = new VolBean();
		volBean.setDate_D(dd);
		volBean.setDate_A(da);
		volBean.setLieu_D(textbox_lieu_d.getText());
		volBean.setLieu_A(textbox_lieu_a.getText());
		volBean.setTarif(doublebox_tarif.getValue().floatValue());
		volBean.setHotels(selected_hotels);

		final VolServiceAsync volIface;
		volIface = GWT.create(VolService.class);

		volIface.save(volBean, new AsyncCallback<String>() {
			@Override
			public void onFailure(Throwable caught) {
				infoDanger(caught.toString());
			}

			@Override
			public void onSuccess(String result) {
				infoSuccess(result);
				History.newItem(Constantes.VOLCONSULTWB);
			}
		});
	}

	private void update() {
		if (textbox_lieu_d.getText().length() == 0
				|| textbox_lieu_a.getText().length() == 0
				|| doublebox_tarif.getText().length() == 0
				|| selected_hotels == null
				|| selected_hotels.size() == 0) {
			infoDanger("Informations incomplètes");
			return;
		}

		infoDangerHide();
		setHourAndMinutes(dd, timePicker_d);
		setHourAndMinutes(da, timePicker_a);

		if (dd.after(da)) {
			infoDanger("La date de départ doit être antérieure à la date d'arrivée");
			return;
		}

		selected_vol.setDate_D(dd);
		selected_vol.setDate_A(da);
		selected_vol.setLieu_D(textbox_lieu_d.getText());
		selected_vol.setLieu_A(textbox_lieu_a.getText());
		selected_vol.setTarif(doublebox_tarif.getValue().floatValue());
		selected_vol.setHotels(selected_hotels);

		final VolServiceAsync volIface;
		volIface = GWT.create(VolService.class);

		volIface.update(selected_vol,
				new AsyncCallback<String>() {
					@Override
					public void onFailure(Throwable caught) {
						infoDanger(caught.toString());
					}

					@Override
					public void onSuccess(String result) {
						infoSuccess(result);
						consultPanel.setVisible(true);
						updatePanel.setVisible(false);
						tab_vols.redraw();
						label_titre.setText("Tous les vols");
					}
				});
	}

	private void delete(VolBean volBean, final int index) {
		final VolServiceAsync volIface;
		volIface = GWT.create(VolService.class);
		infoDangerHide();
		volIface.delete(volBean,
				new AsyncCallback<String>() {
					@Override
					public void onFailure(Throwable caught) {
						infoDanger(caught.toString());
					}

					@Override
					public void onSuccess(String result) {
						infoSuccess(result);
						ldp.getList().remove(index);
						ldp.refresh();
						tab_vols.redraw();
					}
				});
	}

	private void loadVols() {
		consultPanel.setVisible(true);
		savePanel.setVisible(false);
		updatePanel.setVisible(false);

		final VolServiceAsync volIface;
		volIface = GWT.create(VolService.class);

		infoDangerHide();
		volIface.selectAll(new AsyncCallback<ArrayList<VolBean>>() {
			@Override
			public void onFailure(Throwable caught) {
				infoDanger(caught.toString());
			}

			@Override
			public void onSuccess(ArrayList<VolBean> result) {
				vols = result;
				final HotelServiceAsync hotelIface;
				hotelIface = GWT.create(HotelService.class);

				infoDangerHide();
				hotelIface.selectAll(new AsyncCallback<ArrayList<HotelBean>>() {
					@Override
					public void onFailure(Throwable caught) {
						infoDanger(caught.toString());
					}

					@Override
					public void onSuccess(ArrayList<HotelBean> result) {
						mainPanel.add(label_titre);
						FlowPanel hr = new FlowPanel("hr");
						mainPanel.add(hr);
						hotels = result;
						addClickHandler_update(button_submit);
						buildHotelTable();
						loadVolForm(updatePanel);
						loadConsultPanel();
					}
				});

			}
		});
	}

	private void loadHotels() {
		consultPanel.setVisible(false);
		savePanel.setVisible(true);
		updatePanel.setVisible(false);

		final HotelServiceAsync hotelIface;
		hotelIface = GWT.create(HotelService.class);

		infoDangerHide();
		hotelIface.selectAll(new AsyncCallback<ArrayList<HotelBean>>() {
			@Override
			public void onFailure(Throwable caught) {
				infoDanger(caught.toString());
			}

			@Override
			public void onSuccess(ArrayList<HotelBean> result) {
				hotels = result;
				loadSavePanel();
			}
		});
	}

	private void addVolColumns() {
		Column<VolBean, String> ld_column = new Column<VolBean, String>(new TextCell()) {
			@Override
			public String getValue(VolBean vol) {
				return vol.getLieu_D();
			}
		};
		tab_vols.addColumn(ld_column, "Origine");

		Column<VolBean, String> la_column = new Column<VolBean, String>(new TextCell()) {
			@Override
			public String getValue(VolBean vol) {
				return String.valueOf(vol.getLieu_A());
			}
		};
		tab_vols.addColumn(la_column, "Destination");

		Column<VolBean, String> dd_column = new Column<VolBean, String>(new TextCell()) {
			@Override
			public String getValue(VolBean vol) {
				return dateToString(vol.getDate_D());
			}
		};
		tab_vols.addColumn(dd_column, "Départ");

		Column<VolBean, String> hd_column = new Column<VolBean, String>(new TextCell()) {
			@Override
			public String getValue(VolBean vol) {
				return hourToString(vol.getDate_D());
			}
		};
		tab_vols.addColumn(hd_column, "Heure");

		Column<VolBean, String> da_column = new Column<VolBean, String>(new TextCell()) {
			@Override
			public String getValue(VolBean vol) {
				return dateToString(vol.getDate_A());
			}
		};
		tab_vols.addColumn(da_column, "Arrivée");

		Column<VolBean, String> ha_column = new Column<VolBean, String>(new TextCell()) {
			@Override
			public String getValue(VolBean vol) {
				return hourToString(vol.getDate_A());
			}
		};
		tab_vols.addColumn(ha_column, "Heure");

		Column<VolBean, Number> tarif_column = new Column<VolBean, Number>(new NumberCell()) {
			@Override
			public Float getValue(VolBean vol) {
				return vol.getTarif();
			}
		};
		tab_vols.addColumn(tarif_column, "Tarif (€)");

        // Bouton editer

        ButtonCell editButton = new ButtonCell() {
            // A native button cell doesn't have the gwt-button class, which makes it
            // look weird next to other gwt buttons. Fix that here.
            @Override
            public void render(
                    final Context context,
                    final SafeHtml data,
                    final SafeHtmlBuilder sb) {
                sb.appendHtmlConstant("<button type=\"button\" class=\"btn btn-default\" tabindex=\"0\">");
                sb.appendHtmlConstant("<span class=\"icon-pencil\"></span>");
                sb.appendHtmlConstant("</button>");
            }
        };
        Column<VolBean, String> action_edit_column = new Column<VolBean, String>(editButton) {
            @Override
			public String getValue(VolBean object) {
				return "~";
			}
		};
		action_edit_column.setFieldUpdater(new FieldUpdater<VolBean, String>() {
            @Override
            public void update(int index, VolBean volBean, String value) {
                selected_vol = volBean;
                consultPanel.setVisible(false);
                savePanel.setVisible(false);
				updatePanel.setVisible(true);
				loadUpdatePanel();
            }
        });
        tab_vols.addColumn(action_edit_column, "Editer");

        // Bouton supprimer
        ButtonCell supprimeButton = new ButtonCell() {
            // A native button cell doesn't have the gwt-button class, which makes it
            // look weird next to other gwt buttons. Fix that here.
            @Override
            public void render(
                    final Context context,
                    final SafeHtml data,
                    final SafeHtmlBuilder sb) {
                sb.appendHtmlConstant("<center><button type=\"button\" class=\"btn btn-danger\" tabindex=\"0\">");
                sb.appendHtmlConstant("<span class=\"icon-white icon-trash\"></span>");
                sb.appendHtmlConstant("</button></center>");
            }
        };

        Column<VolBean, String> action_delete_column = new Column<VolBean, String>(supprimeButton) {
            @Override
			public String getValue(VolBean object) {
				return "x";
			}
		};
		action_delete_column.setFieldUpdater(new FieldUpdater<VolBean, String>() {
            @Override
            public void update(int index, VolBean volBean, String value) {
                if (volBean.getPanneaux() == 0) {
                    delete(volBean, index);
                } else {
                    infoDanger("Appartient a un panneau");
                }
            }
        });

        tab_vols.addColumnStyleName(tab_vols.getColumnCount() - 1, "action-cell");
        tab_vols.addColumnStyleName(tab_vols.getColumnCount(), "action-cell");
        tab_vols.addColumn(action_delete_column, "Supprimer");
        tab_vols.setRowCount(vols.size(), true);
        tab_vols.setRowData(0, vols);

		ldp.addDataDisplay(tab_vols);
		ldp.setList(vols);
	}

	private void addHotelColumns() {
		Column<HotelBean, Boolean> rowSelectColumn = new Column<HotelBean, Boolean>(new CheckboxCell(true, false)) {
			@Override
			public Boolean getValue(HotelBean object) {
				Boolean result;
				// check for null value and return null;
				if (object == null || object.getIdhotel() == null) {
					result = null;
				} else {  // get value from the selection model
					result = selectionModel.isSelected(object);
				}
				return result;
			}
		};
		tab_hotels.addColumn(rowSelectColumn, "Lier");

		Column<HotelBean, String> nom_column = new Column<HotelBean, String>(new TextCell()) {
			@Override
			public String getValue(HotelBean hotel) {
				return hotel.getNom();
			}
		};
		tab_hotels.addColumn(nom_column, "Nom");

		Column<HotelBean, String> adresse_column = new Column<HotelBean, String>(new TextCell()) {
			@Override
			public String getValue(HotelBean hotel) {
				return hotel.getAdresse();
			}
		};
		tab_hotels.addColumn(adresse_column, "Adresse");

		Column<HotelBean, Number> standing_column = new Column<HotelBean, Number>(new NumberCell()) {
			@Override
			public Number getValue(HotelBean hotel) {
				return hotel.getStanding();
			}
		};
		tab_hotels.addColumn(standing_column, "Standing");

		Column<HotelBean, Number> tarif_column = new Column<HotelBean, Number>(new NumberCell()) {
			@Override
			public Float getValue(HotelBean hotel) {
				return hotel.getTarif();
			}
		};
		tab_hotels.addColumn(tarif_column, "Tarif (€)");

		tab_hotels.setRowCount(hotels.size(), true);
		tab_hotels.setRowData(0, hotels);

		ListDataProvider<HotelBean> ldp = new ListDataProvider<>();
		ldp.addDataDisplay(tab_hotels);
		ldp.setList(hotels);
	}

	private void setHourAndMinutes(Date d, ListBox timepicker) {
		String hour = timepicker.getSelectedValue().split(":")[0];
		String minutes = timepicker.getSelectedValue().split(":")[1];
		d.setHours(Integer.parseInt(hour));
		d.setMinutes(Integer.parseInt(minutes));
	}

	private String dateToString(Date d) {
		DateTimeFormat dtf = DateTimeFormat.getFormat("dd-MM-yyyy");
		return dtf.format(d);
	}

	private String hourToString(Date d) {
		DateTimeFormat dtf = DateTimeFormat.getFormat("HH:mm");
		return dtf.format(d);
	}
}